package cn.mujiankeji.mbrowser.功能.下载.引擎

import cn.mujiankeji.mbrowser.功能.下载.模型.下载任务
import cn.mujiankeji.mbrowser.功能.下载.模型.下载状态
import io.ktor.client.HttpClient
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.launch
import java.util.concurrent.ConcurrentHashMap

/**
 * Ktor基础下载引擎抽象类。
 * 实现了 [下载引擎接口]，为基于Ktor的下载提供了通用的HTTP下载核心功能。
 * 子类需要实现具体的下载逻辑。
 *
 * @property httpClient Ktor HTTP客户端实例，用于执行网络请求。
 * @property engineScope 下载引擎自身管理的协程作用域。
 */
abstract class Ktor下载引擎基础(
    protected val httpClient: HttpClient,
    protected val engineScope: CoroutineScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
) : 下载引擎接口 {

    // 用于跟踪活动下载任务的Job和状态Flow
    protected val activeJobs = ConcurrentHashMap<String, Job>()
    protected val taskStateFlows = ConcurrentHashMap<String, MutableStateFlow<下载任务>>()

    override fun 开始下载(任务: 下载任务): Flow<下载任务> {

        // 如果任务已在进行中，则返回现有的Flow
        activeJobs[任务.id]?.let {
            if (it.isActive) {
                return taskStateFlows[任务.id]?.asStateFlow() ?: flow { emit(任务.copy(状态 = 下载状态.失败, 错误信息 = "无法找到任务状态Flow")) }
            }
        }

        val initialState = 任务.copy(状态 = 下载状态.等待中, 已下载大小 = 0L) // 确保从头开始
        val stateFlow = MutableStateFlow(initialState)
        taskStateFlows[任务.id] = stateFlow

        val job = engineScope.launch {
            try {
                stateFlow.value = initialState.copy(状态 = 下载状态.正在下载)
                执行下载(initialState, stateFlow)
            }
            catch (e: Exception) {
                if (e is kotlinx.coroutines.CancellationException) {
                    // 协程被取消，可能是暂停或取消操作
                    // 状态应已在暂停/取消方法中处理
                    // 如果stateFlow中的状态仍然是正在下载，则更新为失败
                    if (stateFlow.value.状态 == 下载状态.正在下载) {
                         stateFlow.value = stateFlow.value.copy(状态 = 下载状态.失败, 错误信息 = "下载被意外取消: ${e.message}")
                    }
                } else {
                    stateFlow.value = stateFlow.value.copy(状态 = 下载状态.失败, 错误信息 = e.message ?: "未知下载错误")
                }
            } finally {
                // 无论成功或失败，如果不是用户主动暂停，都从activeJobs中移除
                if (stateFlow.value.状态 != 下载状态.已暂停) {
                    activeJobs.remove(任务.id)
                     // 如果任务不是已完成或已暂停，则也从 taskStateFlows 移除，避免内存泄漏
                    if (stateFlow.value.状态 != 下载状态.已完成) {
                        taskStateFlows.remove(任务.id)
                    }
                }
            }
        }
        activeJobs[任务.id] = job
        
        return stateFlow.asStateFlow()
            .onCompletion { // Flow收集结束时（通常是下载完成或作用域取消）
                // 确保Job被清理
                if (it != null && it !is kotlinx.coroutines.CancellationException) { // 如果是因为错误完成
                     activeJobs[任务.id]?.cancel("Flow collection completed with error")
                }
                if (stateFlow.value.状态 != 下载状态.已暂停 && stateFlow.value.状态 != 下载状态.已完成) {
                    activeJobs.remove(任务.id)
                    taskStateFlows.remove(任务.id)
                }
            }
            .catch { e ->
                // Flow 收集器端的错误处理
                 val currentTaskState = taskStateFlows[任务.id]?.value ?: 任务
                 taskStateFlows[任务.id]?.value = currentTaskState.copy(
                     状态 = 下载状态.失败,
                     错误信息 = "Flow收集错误: ${e.message}"
                 )
            }
    }

    override fun 恢复下载(任务: 下载任务): Flow<下载任务> {
        // 与开始下载类似，但任务状态应为已暂停，并从已下载大小继续
        activeJobs[任务.id]?.let {
            if (it.isActive) {
                return taskStateFlows[任务.id]?.asStateFlow() ?: flow { emit(任务.copy(状态 = 下载状态.失败, 错误信息 = "无法找到任务状态Flow")) }
            }
        }
        // 确保任务是从暂停状态恢复
        if (任务.状态 != 下载状态.已暂停 && 任务.状态 != 下载状态.失败) { // 允许从失败状态重试恢复
            return flow { emit(任务.copy(状态 = 下载状态.失败, 错误信息 = "任务不处于可恢复状态")) }
        }

        val stateFlow = taskStateFlows[任务.id] ?: MutableStateFlow(任务)
        taskStateFlows[任务.id] = stateFlow // 确保存在
        stateFlow.value = 任务.copy(状态 = 下载状态.正在下载, 错误信息 = null) // 清除旧错误信息

        val job = engineScope.launch {
             try {
                执行下载(stateFlow.value, stateFlow)
            } catch (e: Exception) {
                if (e is kotlinx.coroutines.CancellationException) {
                    if (stateFlow.value.状态 == 下载状态.正在下载) {
                         stateFlow.value = stateFlow.value.copy(状态 = 下载状态.失败, 错误信息 = "下载被意外取消: ${e.message}")
                    }
                } else {
                    stateFlow.value = stateFlow.value.copy(状态 = 下载状态.失败, 错误信息 = e.message ?: "未知下载错误")
                }
            } finally {
                if (stateFlow.value.状态 != 下载状态.已暂停) {
                    activeJobs.remove(任务.id)
                    if (stateFlow.value.状态 != 下载状态.已完成) {
                        taskStateFlows.remove(任务.id)
                    }
                }
            }
        }
        activeJobs[任务.id] = job

        return stateFlow.asStateFlow()
            .onCompletion { 
                if (it != null && it !is kotlinx.coroutines.CancellationException) {
                     activeJobs[任务.id]?.cancel("Flow collection completed with error")
                }
                 if (stateFlow.value.状态 != 下载状态.已暂停 && stateFlow.value.状态 != 下载状态.已完成) {
                    activeJobs.remove(任务.id)
                    taskStateFlows.remove(任务.id)
                }
            }
            .catch { e ->
                 val currentTaskState = taskStateFlows[任务.id]?.value ?: 任务
                 taskStateFlows[任务.id]?.value = currentTaskState.copy(
                     状态 = 下载状态.失败,
                     错误信息 = "Flow收集错误: ${e.message}"
                 )
            }
    }

    override suspend fun 暂停下载(任务Id: String) {
        activeJobs[任务Id]?.cancel("用户暂停下载") // 取消Job
        activeJobs.remove(任务Id) // 从活动Job中移除

        taskStateFlows[任务Id]?.let { stateFlow ->
            val currentTask = stateFlow.value
            if (currentTask.状态 == 下载状态.正在下载 || currentTask.状态 == 下载状态.等待中) {
                stateFlow.value = currentTask.copy(状态 = 下载状态.已暂停)
            }
            // 注意：已暂停的任务状态Flow会保留在taskStateFlows中，以便恢复时使用
        }
    }

    override suspend fun 取消下载(任务Id: String) {
        activeJobs[任务Id]?.cancel("用户取消下载")
        activeJobs.remove(任务Id)

        taskStateFlows[任务Id]?.let { stateFlow ->
            val currentTask = stateFlow.value
            stateFlow.value = currentTask.copy(状态 = 下载状态.已取消, 已下载大小 = 0) // 重置进度
        }
        taskStateFlows.remove(任务Id) // 从状态Flows中也移除

    }

    override suspend fun 查询下载状态(任务Id: String): 下载任务? {
        return taskStateFlows[任务Id]?.value
    }

    /**
     * 核心下载逻辑，由子类（如普通文件下载、M3U8下载）具体实现。
     * 此方法负责执行实际的HTTP请求、数据读取、文件写入，并通过 [taskStateFlow] 更新下载进度和状态。
     * 它应该能够根据 [initialTask] 中的 `已下载大小` 和 `请求头` 来处理断点续传。
     *
     * @param initialTask 启动或恢复下载时的初始任务状态。
     * @param taskStateFlow 用于发射任务状态和进度更新的 MutableStateFlow。
     *                      实现者应在下载过程中（如每下载一定数据块后）更新此Flow的值，
     *                      并在下载完成时设置为 [下载状态.已完成]，或在出错时设置为 [下载状态.失败] 并附带错误信息。
     */
    protected abstract suspend fun 执行下载(
        initialTask: 下载任务,
        taskStateFlow: MutableStateFlow<下载任务>
    )

    /**
     * 清理引擎自身资源，例如取消所有活动的协程。
     * 当引擎不再需要时（例如应用关闭或DI作用域结束）调用。
     */
    open fun 销毁() {
        engineScope.cancel("下载引擎关闭")
        activeJobs.clear()
        taskStateFlows.clear()
    }



} 